<?php
final class Installer {
    /**
     *
     * @var Smarty
     */
    private static $smarty;
    private static $lang;

    public static function init() {
        self::initSmarty();
        self::loadLang();
        $installError = false;
        if (!is_writable(dirname(__FILE__) . '/../cache/smarty')) {
            $installError = self::$lang['cannotWriteToCache'];
        }
        if (!is_writable(dirname(__FILE__) . '/../config.php')) {
            $installError = self::$lang['cannotWriteToConfig'];
        }
        if (!is_writable(dirname(__FILE__) . '/../files')) {
            $installError = self::$lang['cannotWriteToFiles'];
        }
        self::$smarty->assign('installError', $installError);
        if (isset($_POST['dbServer'])) {
            if (!self::isValid($_POST)) {
                $_SESSION['installForm'] = $_POST;
                header('Location: ' . WEB_DIR . '/');
                return;
            }
            self::prepareImageBackground();
            self::writeConfig();
            self::writeDB();
            $_SESSION['installer'] = 'display confirmation';
            header('Location: ' . WEB_DIR . '/');
            return;
        } else {
            if (isset($_SESSION['installer'])) {
                unset($_SESSION['installer']);
                self::$smarty->assign('template', 'confirm');
            } else {
                self::$smarty->assign('template', 'setup');
            }
        }
        self::$smarty->display('page.tpl');
    }
    
    private static function isValid($data) {
        $errors = array();
        foreach ($data as &$item) {
            $item = trim($item);
        }
        if (!$data['adminpass']) {
            $errors[] = 'errorAdminPassRequired';
        }
        if ($data['adminpass'] != $data['adminpass2']) {
            $errors[] = 'errorAdminPassNotSame';
        }
        require_once dirname(__FILE__) . '/../libs/dibi/dibi.php';
        try {
            dibi::connect(array(
                'driver'   => $_POST['driver'],
                'host'     => $_POST['dbServer'],
                'username' => $_POST['dbUser'],
                'password' => $_POST['dbPassword'],
                'database' => $_POST['dbName'],
                'charset'  => 'utf8'
            ));
        } catch (Exception $e) {
            $errors[] = 'errorDBAccess';
        }
        if (!date_default_timezone_set($data['timezone'])) {
            $errors[] = 'errorTimezone';
        }
        if (!is_numeric($data['imageQuality']) ||
                ($data['imageQuality'] < 1) ||
                ($data['imageQuality'] > 100)) {
            $errors[] = 'errorImageQuality';
        }
        if (!preg_match('/^#[0-9a-fA-F]{6}$/', $data['imageBackground'])) {
            $errors[] = 'errorImageBackground';
        }
        foreach ($errors as &$error) {
            $error = self::$lang[$error];
        }
        $_SESSION['errors'] = $errors;
        return empty($errors);
    }
    
    private static function prepareImageBackground() {
        if (!$_POST['imageBackground'] || !preg_match('/^#[0-9a-fA-F]{6}$/',
                $_POST['imageBackground'])) {
            $_POST['imageBackground'] = '#FFFFFF';
        }
        $background = strtolower($_POST['imageBackground']);
        $_POST['imageBackgroundR'] = intval(substr($background, 1, 2), 16);
        $_POST['imageBackgroundG'] = intval(substr($background, 3, 2), 16);
        $_POST['imageBackgroundB'] = intval(substr($background, 5), 16);
    }

    private static function writeDB() {
        dibi::loadFile(dirname(__FILE__) . '/db/' . $_POST['driver'] . '.sql');
        
        $admin = array(
            'login'    => 'admin',
            'password' => sha1($_POST['adminpass'])
        );
        dibi::query("INSERT INTO [Admin] ", $admin);
    }

    private static function writeConfig() {
        $config = array(
            'DB_DRIVER' => $_POST['driver'],
            'TIMEZONE' => $_POST['timezone'],
            'INSTALLED' => true,
            'DB_SERVER' => $_POST['dbServer'],
            'DB_USER' => $_POST['dbUser'],
            'DB_PASSWORD' => $_POST['dbPassword'],
            'DB_NAME' => $_POST['dbName'],
            'LANGUAGE' => $_POST['language'],
            'IMAGE_BACKGROUND_R' => $_POST['imageBackgroundR'],
            'IMAGE_BACKGROUND_G' => $_POST['imageBackgroundG'],
            'IMAGE_BACKGROUND_B' => $_POST['imageBackgroundB'],
            'IMAGE_QUALITY' => $_POST['imageQuality']
        );
        $file = @fopen(dirname(__FILE__) . '/../config.php', 'w');
        if (!is_resource($file)) {
            throw new Exception("Cannot write configuration to config.php");
        }
        fwrite($file, "<?php\nclass Config {\n");
        foreach ($config as $field => $value) {
            fwrite($file, "    const $field = " .
                    (is_string($value) ? "'$value'" : $value) . ";\n");
        }
        fwrite($file, "}\n?>");
        fclose($file);
    }

    private static function loadLang() {
        $language = self::chooseLanguage();
        $langs = glob(dirname(__FILE__) . '/lang/*.ini');
        if (!isset($langs[0])) {
            throw new Exception("No language files for installer!");
        }
        foreach ($langs as &$lang) {
            $lang = substr($lang, strrpos($lang, '/') + 1);
            $lang = substr($lang, 0, strpos($lang, '.'));
        }
        $language = $language ? $language : $langs[0];
        self::$lang = parse_ini_file(dirname(__FILE__) .
                "/lang/$language.ini");
        self::$smarty->assign(self::$lang);
        self::$smarty->assign('languages', $langs);
        self::$smarty->assign('language', $language);
    }

    private static function chooseLanguage() {
        if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
            $langs = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
            foreach ($langs as &$lang) {
                $lang = explode(';', $lang);
                if (isset($lang[1])) {
                    $lang[1] = explode('=', $lang[1]);
                    $lang[1] = (float) $lang[1][1];
                } else {
                    $lang[1] = 1;
                }
            }
            while (count($langs) > 0) {
                $priority = 0;
                foreach ($langs as &$lang) {
                    if ($lang[1] > $priority) {
                        $priority = $lang[1];
                    }
                }
                for ($i = count($langs) - 1; $i >= 0; $i--) {
                    if ($langs[$i][1] == $priority) {
                        if (file_exists(dirname(__FILE__) . '/lang/' .
                                $langs[$i][0] . '.ini')) {
                            return $langs[$i][0];
                        }
                        array_splice($langs, $i, 1);
                    }
                }
            }
        }
        return null;
    }

    private static function initSmarty() {
        require dirname(__FILE__) . '/../libs/smarty/Smarty.class.php';
        self::$smarty = new Smarty();
        self::$smarty->template_dir = dirname(__FILE__) . '/templates';
        self::$smarty->compile_dir = dirname(__FILE__) . '/../cache/smarty';
        if (!is_writable(dirname(__FILE__) . '/../cache/smarty')) {
            $dir = tempnam(null, "tmpTpl");
            unlink($dir);
            mkdir($dir);
            self::$smarty->compile_dir = $dir;
        }
        self::$smarty->config_dir = dirname(__FILE__) .
                '/../libs/smarty/configs';
        self::$smarty->plugins_dir = array(dirname(__FILE__) .
                        '/../libs/smarty/plugins');
        $timezone = date_default_timezone_get();
        $config = array('timezone' => $timezone);
        self::$smarty->assign($config);
    }
}
?>
